package javaforce.utils;

/** File operations (used by jfile)
 *
 * @author pquiring
 */

import java.io.*;
import java.util.*;

import javaforce.*;

public class jfileop extends javax.swing.JFrame {

  /**
   * Creates new form jfileop
   */
  public jfileop() {
    initComponents();
    JFAWT.centerWindow(this);
  }

  /**
   * This method is called from within the constructor to initialize the form.
   * WARNING: Do NOT modify this code. The content of this method is always
   * regenerated by the Form Editor.
   */
  @SuppressWarnings("unchecked")
  // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
  private void initComponents() {

    txt1 = new javax.swing.JLabel();
    progress = new javax.swing.JProgressBar();
    cancel = new javax.swing.JButton();
    txt2 = new javax.swing.JLabel();

    setDefaultCloseOperation(javax.swing.WindowConstants.DO_NOTHING_ON_CLOSE);
    setResizable(false);
    addWindowListener(new java.awt.event.WindowAdapter() {
      public void windowClosing(java.awt.event.WindowEvent evt) {
        formWindowClosing(evt);
      }
    });

    txt1.setText("Status : ...");

    cancel.setText("Cancel");
    cancel.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(java.awt.event.ActionEvent evt) {
        cancelActionPerformed(evt);
      }
    });

    txt2.setText("To : ...");

    javax.swing.GroupLayout layout = new javax.swing.GroupLayout(getContentPane());
    getContentPane().setLayout(layout);
    layout.setHorizontalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addGroup(layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
          .addComponent(txt1, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
          .addComponent(progress, javax.swing.GroupLayout.DEFAULT_SIZE, 353, Short.MAX_VALUE)
          .addGroup(javax.swing.GroupLayout.Alignment.TRAILING, layout.createSequentialGroup()
            .addGap(0, 0, Short.MAX_VALUE)
            .addComponent(cancel))
          .addComponent(txt2, javax.swing.GroupLayout.DEFAULT_SIZE, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE))
        .addContainerGap())
    );
    layout.setVerticalGroup(
      layout.createParallelGroup(javax.swing.GroupLayout.Alignment.LEADING)
      .addGroup(layout.createSequentialGroup()
        .addContainerGap()
        .addComponent(txt1)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(txt2)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED, javax.swing.GroupLayout.DEFAULT_SIZE, Short.MAX_VALUE)
        .addComponent(progress, javax.swing.GroupLayout.PREFERRED_SIZE, 22, javax.swing.GroupLayout.PREFERRED_SIZE)
        .addPreferredGap(javax.swing.LayoutStyle.ComponentPlacement.RELATED)
        .addComponent(cancel)
        .addContainerGap())
    );

    pack();
  }// </editor-fold>//GEN-END:initComponents

  private void cancelActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_cancelActionPerformed
    if (worker != null) {
      worker.abort = true;
    }
  }//GEN-LAST:event_cancelActionPerformed

  private void formWindowClosing(java.awt.event.WindowEvent evt) {//GEN-FIRST:event_formWindowClosing
    if (worker != null) {
      if (worker.abort == true) {
        System.exit(0);
      }
      worker.abort = true;
    }
  }//GEN-LAST:event_formWindowClosing

  /**
   * @param args the command line arguments
   */
  public static void main(String args[]) {
    if (args == null || args.length == 0) {
      System.out.println("Usage:jcp src(s) dest");
      System.out.println("Usage:jmv src(s) dest");
      System.out.println("Usage:jrm file(s)");
      return;
    }
    final String _args[] = args;
    /* Create and display the form */
    java.awt.EventQueue.invokeLater(new Runnable() {
      public void run() {
        jfileop fop = new jfileop();
        fop.setVisible(true);
        fop.start(_args);
      }
    });
  }

  // Variables declaration - do not modify//GEN-BEGIN:variables
  private javax.swing.JButton cancel;
  private javax.swing.JProgressBar progress;
  private javax.swing.JLabel txt1;
  private javax.swing.JLabel txt2;
  // End of variables declaration//GEN-END:variables

  private String cmd[];
  private Worker worker;
  private Timer timer;
  private boolean done;
  private String msg1, msg2;
  private boolean hidetxt2;
  private long amtComplete, amtTodo;

  public void start(String cmd[]) {
    this.cmd = cmd;

    worker = new Worker();
    worker.start();
    timer = new Timer();
    timer.schedule(new TimerTask() {
      public void run() {
        java.awt.EventQueue.invokeLater(new Runnable() {
          public void run() {
            update();
          }
        });
      }
    }, 500, 500);
  }

  private String fit(String in) {
    if (in.length() < 25) {
      return in;
    }
    int idx = in.indexOf(" ");
    String p1 = in.substring(0,idx+1);
    return p1 + "..." + in.substring(in.length() - (25 - p1.length()));
  }

  private synchronized void update() {
    if (msg1 != null) txt1.setText(fit(msg1));
    if (msg2 != null) txt2.setText(fit(msg2));
    if (hidetxt2) {
      hidetxt2 = false;
      txt2.setVisible(false);
    }
    if (amtTodo == 0) return;
    int percent;
    if (done) {
      percent = 100;
    } else {
      percent = (int)(amtComplete * 100 / amtTodo);
    }
    progress.setValue(percent);
  }

  public static class Op {
    public String src, dest;
    public Op(String s, String d) {
      src=s;
      dest=d;
    }
  }

  public class Worker extends Thread {
    ArrayList<Op> ops = new ArrayList<Op>();
    boolean abort;
    public void run() {
      //do the actual work
      try {
        if (cmd[0].equals("cp")) {
          setTitle("Copying...");
          msg1 = "Scanning files...";
          String dest = cmd[cmd.length-1];
          for(int a=1;a<cmd.length-1;a++) {
            ops.add(new Op(cmd[a], dest));
          }
          amtTodo = getFileSize();
          copy();
        } else if (cmd[0].equals("mv")) {
          setTitle("Moving...");
          msg1 = "Scanning files...";
          String dest = cmd[cmd.length-1];
          for(int a=1;a<cmd.length-1;a++) {
            ops.add(new Op(cmd[a], dest));
          }
          amtTodo = getFileCount();
          move();
        } else if (cmd[0].equals("rm")) {
          setTitle("Deleting...");
          hidetxt2 = true;
          amtTodo = getFileCount();
          for(int a=1;a<cmd.length;a++) {
            remove(cmd[a]);
          }
        }
      } catch (Exception e) {}
      System.exit(0);
    }

    public long getFileSize() {
      long size = 0;
      for (int a=0;a<ops.size();a++) {
        if (abort) return 0;
        String src = ops.get(a).src;
        if (new File(src).isDirectory()) {
          size += getDirectorySize(src);
        } else {
          size += getFileSize(src);
        }
      }
      return size;
    }
    public long getFileSize(String file) {
      return new File(file).length();
    }
    public long getDirectorySize(String dir) {
      long size = 4096;
      File files[] = new File(dir).listFiles();
      if (files == null) return 0;
      for(int a=0;a<files.length;a++) {
        if (abort) return 0;
        if (files[a].isDirectory()) {
          size += getDirectorySize(files[a].getAbsolutePath());
        } else {
          size += getFileSize(files[a].getAbsolutePath());
        }
      }
      return size;
    }

    public long getFileCount() {
      long size = 0;
      for (int a=0;a<ops.size();a++) {
        if (abort) return 0;
        String src = ops.get(a).src;
        if (new File(src).isDirectory()) {
          size += getDirectoryCount(src);
        } else {
          size += getFileCount(src);
        }
      }
      return size;
    }
    public long getFileCount(String file) {
      return 1;
    }
    public long getDirectoryCount(String dir) {
      long size = 1;
      File files[] = new File(dir).listFiles();
      if (files == null) return 0;
      for(int a=0;a<files.length;a++) {
        if (abort) return 0;
        if (files[a].isDirectory()) {
          size += getDirectorySize(files[a].getAbsolutePath());
        } else {
          size += getFileSize(files[a].getAbsolutePath());
        }
      }
      return size;
    }

    public void copy() {
      while (ops.size() > 0) {
        if (abort) return;
        Op op = ops.remove(0);
        File srcFile = new File(op.src);
        if (srcFile.isDirectory()) {
          copyDirectory(op.src, op.dest + "/" + srcFile.getName());
        } else {
          copyFile(op.src, op.dest);
        }
      }
    }
    public final static int bufsiz = 64 * 1024;
    public byte buf[] = new byte[bufsiz];
    public void copyFile(String src, String destFolder) {
      msg1 = "Copying " + src;
      msg2 = "To " + destFolder;
      long amtBefore = amtComplete;
      FileInputStream fis = null;
      FileOutputStream fos = null;
      File srcFile = new File(src);
      File destFile = new File(destFolder, srcFile.getName());
      long size = srcFile.length();
      try {
        fis = new FileInputStream(srcFile);
        fos = new FileOutputStream(destFile);
        long copied = 0;
        long left = size;
        int toRead;
        while (copied < size) {
          if (abort) throw new Exception("abort");
          if (left > bufsiz) {
            toRead = bufsiz;
          } else {
            toRead = (int)left;
          }
          int read = fis.read(buf, 0, toRead);
          if (read <= 0) {
            throw new Exception("read error");
          }
          fos.write(buf, 0, read);
          copied += read;
          left -= read;
        }
        fis.close();
        fis = null;
        fos.close();
        fos = null;
      } catch (Exception e) {
        try { if (fis != null) fis.close(); } catch (Exception e1) {}
        try { if (fos != null) fos.close(); } catch (Exception e2) {}
        destFile.delete();
        if (abort) return;
        if (JFAWT.showConfirm("Copy Error", "Failed to copy:" + src + "\nRetry?")) {
          ops.add(new Op(src, destFolder));
          amtComplete = amtBefore;
        } else {
          amtComplete = amtBefore + size;
        }
      }
    }
    public void copyDirectory(String src, String dest) {
      msg1 = "Copying " + src;
      msg2 = "To " + dest;
      File srcFolder = new File(src);
      File destFolder = new File(dest);
      while ((!destFolder.exists()) && !destFolder.mkdir()) {
        if (abort) return;
        if (!JFAWT.showConfirm("Copy Error", "Failed to create folder:" + destFolder.getAbsolutePath() + "\nRetry?")) {
          return;
        }
      }
      amtComplete += 4096;
      File files[] = srcFolder.listFiles();
      if (files == null) return;
      for(int a=0;a<files.length;a++) {
        if (abort) return;
        boolean isDir = files[a].isDirectory();
        if (isDir) {
          copyDirectory(files[a].getAbsolutePath(), dest + "/" + files[a].getName());
        } else {
          copyFile(files[a].getAbsolutePath(), dest);
        }
      }
    }

    public void move() {
      while (ops.size() > 0) {
        if (abort) return;
        Op op = ops.remove(0);
        move(op.src, op.dest);
      }
    }
    public void move(String src, String dest) {
      msg1 = "Moving " + src;
      msg2 = "To " + dest;
      File srcFile = new File(src);
      File destFile = new File(dest, srcFile.getName());
      while (!srcFile.renameTo(destFile)) {
        if (!JFAWT.showConfirm("Move Error", "Failed to move:" + src + "\nRetry?")) {
          return;
        }
      }
      amtComplete++;
    }

    public void remove(String name) {
      if (abort) return;
      msg1 = "Deleting " + name;
      File file = new File(name);
      if (file.isDirectory()) {
        removeDirectory(name);
      } else {
        while (!file.delete()) {
          if (!JFAWT.showConfirm("Delete Error", "Failed to delete:" + name + "\nRetry?")) {
            return;
          }
        }
        amtComplete++;
      }
    }
    public void removeDirectory(String name) {
      File files[] = new File(name).listFiles();
      msg1 = "Deleting " + name;
      if (files != null) {
        for(int a=0;a<files.length;a++) {
          if (abort) return;
          remove(files[a].getAbsolutePath());
        }
      }
      File dir = new File(name);
      while (!dir.delete()) {
        if (!JFAWT.showConfirm("Delete Error", "Failed to delete:" + name + "\nRetry?")) {
          return;
        }
      }
      amtComplete++;
    }
  }
}
